package com.lazydong.gui_gateway.route;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.lazydong.gui_gateway.gui.JFrameApp;
import com.lazydong.gui_gateway.gui.LogUtil;
import com.lazydong.gui_gateway.model.ServiceIpAddr;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.event.EventListener;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

/**
 * 动态路由组件
 */
@Component
public class DynamicRouteComponent implements ApplicationEventPublisherAware {

    public static final ServiceIpAddr environment = new ServiceIpAddr();

    private final RouteDefinitionWriter routeDefinitionWriter;

    private ApplicationEventPublisher applicationEventPublisher;

    private final Set<String> serviceIdSet = new HashSet<>();

    public DynamicRouteComponent(RouteDefinitionWriter routeDefinitionWriter) {
        this.routeDefinitionWriter = routeDefinitionWriter;
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
        JFrameApp.eventPublisher.set(this.applicationEventPublisher);
    }

    @EventListener(classes = ServiceIpAddr.class)
    public void routeChangeEvent(ServiceIpAddr serviceIpAddr) {
        RouteDefinition routeDefinition = serviceIpAddr2RouteDefinition(serviceIpAddr);
        if (StrUtil.isBlank(serviceIpAddr.getName())) {
            deleteRoute(routeDefinition);
            LogUtil.deleteRouteLog(serviceIpAddr);
            return;
        }
        if (serviceIdSet.contains(routeDefinition.getId())) {
            updateRoute(routeDefinition);
            LogUtil.updateRouteLog(serviceIpAddr);
            return;
        }
        addRoute(routeDefinition);
        LogUtil.addRouteLog(serviceIpAddr);
    }

    @EventListener(classes = ArrayList.class)
    public void routeChangeEvent(ArrayList<ServiceIpAddr> serviceIpAddrs) {
        if (CollectionUtil.isEmpty(serviceIpAddrs)) {
            return;
        }
        System.out.println(serviceIpAddrs.size());
        for (ServiceIpAddr serviceIpAddr : serviceIpAddrs) {
            RouteDefinition routeDefinition = serviceIpAddr2RouteDefinition(serviceIpAddr);
            serviceIdSet.add(routeDefinition.getId());
            routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
        }
        applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this.routeDefinitionWriter));
        for (ServiceIpAddr serviceIpAddr : serviceIpAddrs) {
            if (serviceIpAddr.getServiceId().equals("environment")) {
                continue;
            }
            LogUtil.addRouteLog(serviceIpAddr);
        }
    }


    private void addRoute(RouteDefinition routeDefinition) {
        routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
        serviceIdSet.add(routeDefinition.getId());
        applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this.routeDefinitionWriter));
        System.out.println("addRoute 成功");
    }

    private void deleteRoute(RouteDefinition routeDefinition) {
        routeDefinitionWriter.delete(Mono.just(routeDefinition.getId())).subscribe();
        serviceIdSet.remove(routeDefinition.getId());
        applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this.routeDefinitionWriter));
        System.out.println("deleteRoute 成功");
    }

    public void updateRoute(RouteDefinition routeDefinition) {
        this.routeDefinitionWriter.delete(Mono.just(routeDefinition.getId())).subscribe();
        routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
        applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this.routeDefinitionWriter));
        System.out.println("updateRoute 成功");
    }

    private RouteDefinition serviceIpAddr2RouteDefinition(ServiceIpAddr serviceIpAddr) {
        RouteDefinition routeDefinitionBase = new RouteDefinition();
        routeDefinitionBase.setId(serviceIpAddr.getServiceId());
        routeDefinitionBase.setUri(URI.create(serviceIpAddr.getAddr()));
        routeDefinitionBase.setPredicates(new ArrayList<PredicateDefinition>() {{
            add(new PredicateDefinition("Path=" + serviceIpAddr.getPredicate()));
        }});
        if (serviceIpAddr.getServiceId().equals("environment")) {
            // 环境的优先级设置为最低，因为是拦截的所有
            routeDefinitionBase.setOrder(Ordered.LOWEST_PRECEDENCE);
        }
        return routeDefinitionBase;
    }
}
